/**
 * Class that defines a Facetter
 */
function Facetter( usersettings ) {

/**
 * Please note that when passing in custom templates for 
 * listItemTemplate and orderByTemplate to keep the classes as
 * they are used in the code at other locations as well.
 */

this.defaults = {
  items              : [{a:2,b:1,c:2},{a:2,b:2,c:1},{a:1,b:1,c:1},{a:3,b:3,c:1}],
  indexEntries		 : [],
  baseCount          : 0,
  facets             : {'a': 'Title A', 'b': 'Title B', 'c': 'Title C'},
  resultSelector     : '#results',
  facetSelector      : '#facets',
  facetListSelector  : '#facetListContainer',
  facetContainer     : '<div class=facetsearch id=<%= id %> ></div>',
  facetTitleTemplate : '<h3 class=facettitle><%= title %></h3>',
  facetListContainer : '<div class=facetlist id="facetListContainer"></div>',
  listItemTemplate   : '<div class=facetitem id="<%= id %>"><%= name %> <span class=facetitemcount>(<%= count %>)</span></div>',
  orderByTemplate    : '<div class=orderby><span class="orderby-title">Sort by: </span><ul><% _.each(options, function(value, key) { %>'+
                       '<li class=orderbyitem id=orderby_<%= key %>>'+
                       '<%= value %> </li> <% }); %></ul></div>',
  countTemplate      : '<div class=facettotalcount><%= count %> Results</div>',
  deselectTemplate   : '<div class=deselectstartover>Deselect all filters</div>',
  resultTemplate     : '<div class=facetresultbox><%= name %></div>',
  noResults          : '<div class=results>Sorry, but no items match these criteria</div>',
  orderByOptions     : {'a': 'by A', 'b': 'by B', 'RANDOM': 'by random'},
  state              : {
                         orderBy : false,
                         filters : {}
                       },
  showMoreTemplate   : '<a id=showmorebutton>Show more</a>',
  enablePagination   : true,
  paginationCount    : 20
};

/**
 * This is the first function / variable that gets exported into the 
 * jQuery namespace. Pass in your own settings (see above) to initialize
 * the faceted search
 */
this.settings = {};
this.moreButton = null;

$.extend(this.settings, this.defaults, usersettings);
//$(this.settings.facetSelector).data("settings", this.settings);
this.settings.currentResults = [];
this.settings.facetStore     = {};

/**
 * This is the second function / variable that gets exported into the 
 * jQuery namespace. Use it to update everything if you messed with
 * the settings object
 */
this.facetUpdate = function() {
	this.filter();
	this.order();
	this.updateFacetUI();
	this.updateResults();
};

/**
 * The following section contains the logic of the faceted search
 */

/**
 * initializes all facets and their individual filters 
 */
this.initFacetCount = function() {
  var thissettings = this.settings;
  _.each(thissettings.facets, function(facettitle, facet) {
    thissettings.facetStore[facet] = {};
  });
  _.each(thissettings.items, function(item) {
   // intialize the count to be zero
    _.each(thissettings.facets, function(facettitle, facet) {
      if ($.isArray(item[facet])) {
        _.each(item[facet], function(facetitem) {
          thissettings.facetStore[facet][facetitem.label] = thissettings.facetStore[facet][facetitem.label] || {count: 0, id: _.uniqueId("facet_")};
        });
      } else {
        if (item[facet] !== undefined) {
          thissettings.facetStore[facet][item[facet].label] = thissettings.facetStore[facet][item[facet].label] || {count: 0, id: _.uniqueId("facet_")};
        }
      }
    });
  });
  // sort it:
  _.each(thissettings.facetStore, function(facet, facettitle) {
    var sorted = _.keys(thissettings.facetStore[facettitle]).sort();
    if (thissettings.facetSortOption && thissettings.facetSortOption[facettitle]) {
      sorted = _.union(thissettings.facetSortOption[facettitle], sorted);
    }
    var sortedstore = {};
    _.each(sorted, function(el) {
      sortedstore[el] = thissettings.facetStore[facettitle][el];
    });
    thissettings.facetStore[facettitle] = sortedstore;
  });
};

/**
 * resets the facet count
 */
this.resetFacetCount = function() {
  var thissettings = this.settings;
  _.each(thissettings.facetStore, function(items, facetname) {
    _.each(items, function(value, itemname) {
      thissettings.facetStore[facetname][itemname].count = 0;
    });
  });
};

/**
 * Filters all items from the settings according to the currently 
 * set filters and stores the results in the settings.currentResults.
 * The number of items in each filter from each facet is also updated
 */
this.filter = function() {
  var thissettings = this.settings;
  // first apply the filters to the items
  thissettings.currentResults = _.select(thissettings.items, function(item) {
    var filtersApply = true;
    _.each(thissettings.state.filters, function(filter, facet) {
      if (filtersApply && filter.length) {
  		//alert(facet+'='+filter[0]);
    	if (item[facet] == undefined) {
    		 filtersApply = false;
    	} else {
    		//alert(item[facet]);
	      if ($.isArray(item[facet])) {
	    	  filtersApply = false;
              for (var i in item[facet]) {  
            	  var facetitem = item[facet][i];
            	  if (_.indexOf(filter, facetitem.label) >= 0) {
            		  filtersApply = true;
            		  break;
            	  }
	          };
	      } else {
	        if (_.indexOf(filter, item[facet].label) == -1) {
	          filtersApply = false;
	        }
	      }
    	}
      }
    });
    return filtersApply;
  });
  // Update the count for each facet and item:
  // intialize the count to be zero
  this.resetFacetCount();
  // then reduce the items to get the current count for each facet
  _.each(thissettings.facets, function(facettitle, facet) {
    _.each(thissettings.currentResults, function(item) {
      if ($.isArray(item[facet])) {
        _.each(item[facet], function(facetitem) {
          thissettings.facetStore[facet][facetitem.label].count += 1;
        });
      } else {
        if (item[facet] !== undefined) {
          thissettings.facetStore[facet][item[facet].label].count += 1;
        }
      }
    });
  });
  // remove confusing 0 from facets where a filter has been set
  _.each(thissettings.state.filters, function(filters, facettitle) {
    _.each(thissettings.facetStore[facettitle], function(facet) {
      if (facet.count == 0 && thissettings.state.filters[facettitle].length) facet.count = "+";
    });
  });
  thissettings.state.shownResults = 0;
};

/**
 * Orders the currentResults according to the settings.state.orderBy variable
 */ 
this.order = function() {	
    var thissettings = this.settings;
    
    if (!thissettings.state.orderBy) {
      if ($('#'+thissettings.idInner+'results').is(":visible") ) thissettings.state.orderBy = 'noSort';
      else thissettings.state.orderBy = 'showHide';
    }
    $('.activeorderby[id*="'+thissettings.idInner+'orderby_"]').removeClass("activeorderby");
    $('#'+thissettings.idInner+'orderby_'+thissettings.state.orderBy).addClass("activeorderby");
	$('#'+thissettings.idInner+'orderby_showHide').html(thissettings.currentResults.length+' <img border=0 src="image/sortup.png" title="hide/show results"/>');
    if (thissettings.state.orderBy == 'showHide') {
    	$('#'+thissettings.idInner+'results').hide();
      	$('#'+thissettings.idInner+'_showalllinks').hide();
    	return;
    } else {
    	$('#'+thissettings.idInner+'results').show();
        thissettings.currentResults = _.sortBy(thissettings.currentResults, function(item) {
            if (thissettings.state.orderBy == 'RANDOM') {
              return Math.random()*10000;
            } else {
              return item[thissettings.state.orderBy];
            }
        });
    }
};

/**
 * The given facetname and filtername are activated or deactivated
 * depending on what they were beforehand. This causes the items to
 * be filtered again and the UI is updated accordingly.
 */
this.toggleFilter = function(key, value) {
  this.settings.state.filters[key] = this.settings.state.filters[key] || [] ;
  if (_.indexOf(this.settings.state.filters[key], value) == -1) {
    this.settings.state.filters[key].push(value);
  } else {
    this.settings.state.filters[key] = _.without(this.settings.state.filters[key], value);
    if (this.settings.state.filters[key].length == 0) {
      delete this.settings.state.filters[key];
    }
  }
  this.filter();
  $('#'+this.settings.idInner+'orderby_showHide').html(this.settings.currentResults.length+' <img border=0 src="image/sortup.png" title="hide/show results"/>');
  if (this.settings.state.orderBy == 'showHide') {
  	$('#'+this.settings.idInner+'results').hide();
  	$('#'+this.settings.idInner+'_showalllinks').hide();
  } else {
  	$('#'+this.settings.idInner+'results').show();
  }
};

/**
 * The following section contains the presentation of the faceted search
 */

/**
 * This function is only called once, it creates the facets ui.
 */
this.createFacetUI = function() {
  var itemtemplate  = _.template(this.settings.listItemTemplate);
  var titletemplate = _.template(this.settings.facetTitleTemplate);
  var containertemplate = _.template(this.settings.facetContainer);
  var listcontainertemplate = _.template(this.settings.facetListContainer);
  
  var i = 0;
  var thisFacetter = this;

  $(thisFacetter.settings.facetSelector).html($(containertemplate()));
  _.each(thisFacetter.settings.facets, function(facettitle, facet) {
	var listEntries = _.keys(thisFacetter.settings.facetStore[facet]);
	if (listEntries && listEntries.length > 0) {
	    var facetItem     = {title: facettitle, id:facet , i:i, count:listEntries.length};
	    $(thisFacetter.settings.facetListSelector).append($(titletemplate(facetItem)));
	    i++;
    };
  });
  i=0;
  _.each(thisFacetter.settings.facets, function(facettitle, facet) {
    var item = {i:i};
    var facetlist = $(listcontainertemplate(item));
	var nbEntries = _.keys(thisFacetter.settings.facetStore[facet]).length;
	if (nbEntries > 0 ) {
	    _.each(thisFacetter.settings.facetStore[facet], function(filter, filtername){
	      item = {i:i, id: filter.id, name: filtername, count: filter.count};
	      var filteritem  = $(itemtemplate(item));
	      if (_.indexOf(thisFacetter.settings.state.filters[facet], filtername) >= 0) {
	        filteritem.addClass("activefacet");
	      }
	      facetlist.append(filteritem);
	    });
	    $(thisFacetter.settings.facetSelector).append(facetlist);
	    // add the click event handler to each facet item:
	    _.each(thisFacetter.settings.facetStore[facet], function(filter, filtername){
		    $('#'+thisFacetter.settings.idInner + filter.id).click(function(event){
			      var filter = thisFacetter.getFilterById(this.id);
			      thisFacetter.toggleFilter(filter.facetname, filter.filtername);
			      $(thisFacetter.settings.facetSelector).trigger("facetedsearchfacetclick", filter);
			      thisFacetter.order();
			      thisFacetter.updateFacetUI();
			      thisFacetter.updateResults();
		    });
	    });
	    i++;
	};
  });
  $( '#'+thisFacetter.settings.idInner + 'facets' ).tabs({ selected: -1 });
  // Append total result count
  //countHtml = _.template(thisFacetter.settings.countTemplate, {count: thisFacetter.settings.currentResults.length});
  //$(bottom).append(countHtml);
  // Append deselect filters button
  var deselect = $(thisFacetter.settings.deselectTemplate).click(function(event){
    thisFacetter.settings.state.filters = {};
    thisFacetter.facetUpdate();
  });
  $(thisFacetter.settings.bottomSelector).html(deselect);
  $("#"+thisFacetter.settings.idInner+'-facetSet').append('<a class=andbutton href="#" onclick="javascript:alert(\'AND\');return false;" title="basket"><img src="image/filtre.gif" border=0 title="Search Form"/>AND</a><a class=notbutton href="#" onclick="javascript:alert(\'OR\');return false;" title="basket"><img src="image/filtre.gif" border=0 title="Search Form"/>NOT</a>');
  
  // generate the "order by" options:
  var ordertemplate = _.template(thisFacetter.settings.orderByTemplate);
  var itemHtml = $(ordertemplate({'options': thisFacetter.settings.orderByOptions}));
  $(thisFacetter.settings.bottomSelector).append(itemHtml);
  $('.orderbyitem[id*="'+thisFacetter.settings.idInner+'orderby_"]').each(function(){
	var i = this.id.indexOf("orderby_");
	if (i >= 0) {
	    var id = this.id.substr(i+8); // 8 = length "orderby_"
	    //alert('['+id+']=['+thisFacetter.settings.state.orderBy+']');
	    if (thisFacetter.settings.state.orderBy == id) {
	      $(this).addClass("activeorderby");
	    };
	};
  });
  // add the click event handler to each "order by" item:
  $('.orderbyitem[id*="'+thisFacetter.settings.idInner+'orderby_"]').click(function(event){
		var i = this.id.indexOf("orderby_");
		if (i >= 0) {
		    var id = this.id.substr(i+8); // 8 = length "orderby_"
		    thisFacetter.settings.state.orderBy = id;
		    //alert(id);
		    $(thisFacetter.settings.facetSelector).trigger("facetedsearchorderby", id);
		    thisFacetter.settings.state.shownResults = 0;
		    thisFacetter.order();
		    thisFacetter.updateResults();
		}
  });
  $(thisFacetter.settings.facetSelector).trigger("facetuicreated");
  $("#"+thisFacetter.settings.idInner+'-facetSet').hide();
  $('#'+thisFacetter.settings.idInner+'orderby_showHide').html(thisFacetter.settings.currentResults.length+' <img border=0 src="image/sortup.png" title="hide/show results"/>');
};

/**
 * get a facetname and filtername by the unique id that is created in the beginning
 */
this.getFilterById = function(id) {
	  var thissettings = this.settings;
  var result = false;
  var i = id.indexOf('facet_');
  if (i > 0) id = id.substr(i);
  //alert("id="+id);
  _.all(thissettings.facetStore, function(facet, facetname) {
    return _.all(facet, function(filter, filtername){
      if (filter.id == id) {
        result =  {'facetname': facetname, 'filtername': filtername};
        return false;
      }
      return true;
    });
  });
  return result;
};

/**
 * This function is only called whenever a filter has been added or removed
 * It adds a class to the active filters and shows the correct number for each
 */
this.updateFacetUI = function() {
  var thissettings = this.settings;
  var someActive = false;
  var itemtemplate = _.template(thissettings.listItemTemplate);
  _.each(thissettings.facetStore, function(facet, facetname) {
    _.each(facet, function(filter, filtername){
      var item = {id: filter.id, name: filtername, count: filter.count};
      var filteritem  = $(itemtemplate(item)).html();
      //alert(filter.id+'='+filteritem);
      $("#"+thissettings.idInner+filter.id).html(filteritem);
      if (thissettings.state.filters[facetname] && _.indexOf(thissettings.state.filters[facetname], filtername) >= 0) {
    	someActive = true;
        $("#"+thissettings.idInner+filter.id).addClass("activefacet");
      } else {
        $("#"+thissettings.idInner+filter.id).removeClass("activefacet");
      }
    });
  });
  countHtml = _.template(thissettings.countTemplate, {count: thissettings.currentResults.length});
  $(thissettings.facetSelector + ' .facettotalcount').replaceWith(countHtml);
  if (someActive) {
	  $("#"+thissettings.idInner+'-facetSet').show();
  } else {
	  $("#"+thissettings.idInner+'-facetSet').hide();
  }
};

/**
 * Updates the the list of results according to the filters that have been set
 */
this.updateResults = function() {
  $(this.settings.resultSelector).html(this.settings.currentResults.length == 0 ? this.settings.noResults : "");
  this.showMoreResults();
};

this.showMoreResults = function() {
  var showNowCount = 
      this.settings.enablePagination ? 
	      Math.min(this.settings.currentResults.length - this.settings.state.shownResults, this.settings.paginationCount) : 
	      this.settings.currentResults.length;
  var itemHtml = "";
  if ($(this.settings.resultSelector).is(":visible")) {
	  $('#'+this.settings.idInner+'_showalllinks').show();
	  var template = _.template(this.settings.resultTemplate);
	  for (var i = this.settings.state.shownResults; i < this.settings.state.shownResults + showNowCount; i++) {
	    var item = $.extend(this.settings.currentResults[i], {
	      itemNr    	 : i+1+this.settings.baseCount,
	      totalItemNr    : i,
	      batchItemNr    : i - this.settings.state.shownResults,
	      batchItemCount : showNowCount
	    });
	    itemHtml = itemHtml + template(item);
	  };
	  $(this.settings.resultSelector).append(itemHtml);
	  for (var i = this.settings.state.shownResults; i < this.settings.state.shownResults + showNowCount; i++) {
		    var item = $.extend(this.settings.currentResults[i], {
		      itemNr    	 : i+1+this.settings.baseCount,
		      totalItemNr    : i,
		      batchItemNr    : i - this.settings.state.shownResults,
		      batchItemCount : showNowCount
		    });
		    //alert('#'+this.settings.idInner + '-' + item.uid +'tabs');
		    $( '#'+this.settings.idInner + '-' + item.apprecord +'tabs' ).tabs({ selected: -1 });
		    //$( '#'+this.settings.idInner + '-' + item.uid +'first').removeClass("ui-tabs-selected ui-state-active");
	  }
	  $('#'+this.settings.idInner+'_showalllinks').show();
	  if (!this.moreButton) {
	    this.moreButton = $(this.settings.showMoreTemplate).click(this.showMoreResults);
	    $(this.settings.resultSelector).after(this.moreButton);
	  }
	  if (this.settings.state.shownResults == 0) {
		  this.moreButton.show();
	  }
	  this.settings.state.shownResults += showNowCount;
	  if (this.settings.state.shownResults == this.settings.currentResults.length) {
	    $(this.moreButton).hide();
	  }
	  $(this.settings.resultSelector).trigger("facetedsearchresultupdate");
  };
};

//$(this.settings.facetSelector).empty();
this.initFacetCount();
this.filter();
this.order();
this.createFacetUI();
this.updateResults();
};
